package panda.natalia.gothread.suspend.instrument;

import sun.misc.ClassLoaderUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
 * a simple framework of java fiber
 *  在 META-INF 里定义配置文件, 指定哪些文件是需要做 suspendable 解析的
 *
 * @Author: scpanda2007
 * @Date: 2019/12/4 14:58
 */
public class SimpleSuspendableClassifier implements SuspendableClassifier{

    public static final String PREFIX = "META-INF/";
    public static final String SUSPENDABLES_FILE = "suspendables";
    public static final String SUSPENDABLE_SUPERS_FILE = "suspendable-supers";

    private final Set<String> suspendables = new HashSet<>();
    private final Set<String> suspendableClasses = new HashSet<>();
    private final Set<String> suspendableSupers = new HashSet<>();
    private final Set<String> suspendableSuperInterfaces = new HashSet<>();

    public SimpleSuspendableClassifier(ClassLoader classLoader){
        readFiles(classLoader, SUSPENDABLES_FILE, suspendables, suspendableClasses);
        readFiles(classLoader, SUSPENDABLE_SUPERS_FILE, suspendableSupers, suspendableSuperInterfaces);
    }

    private void readFiles(ClassLoader classLoader, String fileName, Set<String> set, Set<String> classSet){
        try{
            for(Enumeration<URL> susFiles = ClassLoaderHelper.getResources(classLoader, PREFIX + fileName); susFiles.hasMoreElements();){
                URL file = susFiles.nextElement();
                parse(file, set, classSet);
            }
        }catch (IOException ioe){}
    }

    private static void parse(URL file, Set<String> set, Set<String> classSet){
        try(InputStream is = file.openStream();
            Stream<String> lines = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))).lines();
          ) {

            final AtomicInteger count = new AtomicInteger(0);
            lines.sequential().forEach(line -> {
                int linenum = count.incrementAndGet();
                final String s = line.trim();
                if(s.isEmpty()) return; // 空行
                if(s.charAt(0) == '#') return; // 注释
                final int index = s.lastIndexOf('.');
                if(index <= 0) {
                    System.err.println("Can't parse line " + linenum + " in " + file + ": " + line);
                    return;
                }
                final String className = s.substring(0, index).replace('.', '/');
                final String methodName = s.substring(index + 1);
                final String fullName = className + "." + methodName;

                if (methodName.equals("*")) {
                    if(classSet != null) classSet.add(className);
                } else
                    set.add(fullName);
            });

        }catch (IOException ioe){}
    }

    @Override
    public MethodDatabase.SuspendableType isSuspendable(MethodDatabase db, String sourceName, String sourceDebugInfo, boolean isInterface, String className, String superClassName, String[] interfaces, String methodName, String methodDesc, String methodSignature, String[] methodExceptions) {
        return null;
    }
}
